#ifndef __MOYING_COMMU_SUBSCRIBE_H__
#define __MOYING_COMMU_SUBSCRIBE_H__
#include <moying_comm_lib/moying_commu_base.h>
#include <moying_comm_lib/receive_callback.h>
#include <moying_comm_lib/utility.h>
#include <memory>

namespace moying
{
namespace communication
{

struct SubData // 订阅数据结构
{
  std::string content_;
  CallbackBasePtr func_;
  bool log_;
  SubData()
  {
    
  }
  SubData(const std::string &content, CallbackBasePtr func, bool log) :
  content_(content), func_(func), log_(log)
  {
  }
};

class MoyingCommuSubscribe : public MoyingCommuBase
{
public:
  MoyingCommuSubscribe(const std::string &url, const std::string &identity);
  MoyingCommuSubscribe(const std::string &ip, const unsigned int port, const std::string &identity);
  MoyingCommuSubscribe(const std::string &content, const std::string &ip, const unsigned int port, const std::string &identity, RecvCall func, bool is_thread_safe = false);
  ~MoyingCommuSubscribe() noexcept;

  template<typename P>
  bool subscribe(const std::string &content, void(*sub_cb)(const P&), bool log = true)
  {
    if(proto_types_.find(content) == proto_types_.end())
      proto_types_[content] = new P();
    return subscribe(content, std::make_shared<SubscribeCallback<P>>(sub_cb), log);
  }

  template<typename P>
  bool subscribe(const std::string &content, std::function<void(const P&)> sub_cb, bool log = true)
  {
    if(proto_types_.find(content) == proto_types_.end()){
      proto_types_[content] = new P();
    }
    return subscribe(content, std::make_shared<SubscribeCallback<P>>(sub_cb), log);
  }

  template<typename P, typename T>
  bool subscribe(const std::string& content, void(T::*fp)(const P&), std::shared_ptr<T> obj, bool log = true)
  {
    if(proto_types_.find(content) == proto_types_.end())
      proto_types_[content] = new P();
    return subscribe(content, std::make_shared<SubscribeCallback<P>>(boost::bind(fp, obj, _1)), log);
  }

  template<typename P, typename T>
  bool subscribe(const std::string& content, void(T::*fp)(const P&), T* obj, bool log = true)
  {
    if(proto_types_.find(content) == proto_types_.end())
      proto_types_[content] = new P();
    return subscribe(content, std::make_shared<SubscribeCallback<P>>(boost::bind(fp, obj, _1)), log);
  }

  bool unsubscribe(const std::string &content);
  
  virtual bool run() override;
  virtual bool close() override;
private:
  void createLoop();
  void printPackWrapper(const std::string &content, bytes_ptr pack, int thread_id);
  bool alterSubContent(const std::string &content, bool add);
  bool subscribe(const std::string& content, CallbackBasePtr cb, bool log);
private:
//  zmq::context_t ctx_;   // 上下文环境
  zmq::socket_t socket_; // 套接字对象
  std::map<std::string, SubData> sub_cbs_;
  std::map<std::string, ::google::protobuf::Message*> proto_types_;
};

typedef std::shared_ptr<MoyingCommuSubscribe> MoyingCommuSubscribePtr;

} // namespace communication
} // namespace moying

#endif // __MOYING_COMMU_SUBSCRIBE_H__
